package com.twu.biblioteca;

import java.io.*;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

public class BibliotecaApp {
    private PrintStream output;
    private Scanner consoleInput;
    private Library library;
    public final static String WELCOME_MESSAGE = "Welcome to Biblioteca!";
    private HashMap<Integer, MenuItem> menuOptionList = new HashMap<Integer, MenuItem>();
    private ReturnBookMenuItem returnBookMenuItem;
    private CheckoutBookMenuItem checkOutBookMenuItem;
    private AccountManager accountManager;
    private User loggedInUser;

    public BibliotecaApp(PrintStream ps, InputStream inputStream, Library lib, List<User> userDB) {
        this.output = ps;
        this.library = lib;
        this.consoleInput = new Scanner(inputStream).useDelimiter("\\n");
        this.accountManager = new AccountManager(userDB);
        this.loggedInUser = null;
        initialiseMenuOptionList();
    }

    private void initialiseMenuOptionList() {
        menuOptionList.put(new Integer(1), new ListAllBooksMenuItem("List all available books"));
        menuOptionList.put(new Integer(2), new ListAllMoviesMenuItem("List all available movies"));
        menuOptionList.put(new Integer(3), new UserLoginMenuItem("Login"));
        menuOptionList.put(new Integer(4), new ViewUserDetailsMenuItem("User details"));
    }

    public void start() throws IOException {
        output.println(WELCOME_MESSAGE);
        displayMenuOptions();
        while(consoleInput.hasNext()){
            selectMenuOption();
        }
    }

    private void displayMenuOptions() {
        output.println("Select an option:");
        for(int m : menuOptionList.keySet()){
            output.println(Integer.toString(m) + ". " + menuOptionList.get(m).toString());
        }
    }

    private void selectMenuOption() throws IOException {
        int selectedMenuItem = consoleInput.nextInt();
        if(!menuOptionList.containsKey(selectedMenuItem)){
            output.println("Select a valid option!");
        } else {
            menuOptionList.get(selectedMenuItem).execute();
        }
    }

    private void checkOutBook(String bookTitle)  {
        try {
                library.checkOutBook(bookTitle, loggedInUser);
                output.println("Thank you! Enjoy the book");
        } catch (BookUnavailableException e) {
                output.println(e.getMessage());
        }
    }

    private void returnBook(String bookTitle) {
        try {
                library.returnBook(bookTitle, loggedInUser);
                output.println("Thank you for returning the book");
        } catch (BookUnavailableException e) {
                output.println(e.getMessage());
        }
    }

    private void checkOutMovie(String movie) {
        try {
            library.checkOutMovie(movie, loggedInUser);
            output.println("Thank you! Enjoy the movie");
        } catch (MovieUnavailableException e) {
            output.println(e.getMessage());
        }
    }

    private void returnMovie(String movie) {
        try {
            library.returnMovie(movie, loggedInUser);
            output.println("Thank you for returning the movie");
        } catch (MovieUnavailableException e) {
            output.println(e.getMessage());
        }
    }

    private void login(String libNumber, String password) {
        output.println("You are logged in");
    }

    private class ListAllBooksMenuItem implements MenuItem {
        private final String description;

        public ListAllBooksMenuItem(String s) {
            this.description = s;
        }

        public void execute() throws IOException {
            if(!library.hasAvailableBooks()) {
                output.println("There are no books in the library");
            } else {
                output.println("Available books:");
                for (String book : library.getAvailableBookList()) {
                    output.println(book);
                }
                output.println("Enter 1 to checkout a book or 2 to return a book");
                if(consoleInput.hasNext()){ displaySubMenuOptions(); }
            }
        }

        private void displaySubMenuOptions() throws IOException {
            int selectedSubMenuOption = consoleInput.nextInt();
            if(selectedSubMenuOption == 1){
                new CheckoutBookMenuItem("Enter the title of the book to checkout").execute();
            } else if(selectedSubMenuOption == 2){
                new ReturnBookMenuItem("Enter the title of the book to return").execute();
            }

        }

        @Override
        public String toString() {
            return description;
        }
    }

    private class ListAllMoviesMenuItem implements MenuItem {
        private final String description;

        public ListAllMoviesMenuItem(String description) {
            this.description = description;
        }

        public void execute() throws IOException {
            if(!library.hasAvailableMovies()){
                output.println("There are no movies in the library");
            } else {
                output.println("Available movies");
                for(String movie : library.getAvailableMovieList()){
                    output.println(movie);
                }
                output.println("Enter 1 to checkout a movie or 2 to return a movie");
                if(consoleInput.hasNext()) { displaySubMenuOptions();}
            }
        }

        private void displaySubMenuOptions() throws IOException {
            int selectedSubMenuOption = consoleInput.nextInt();
            if(selectedSubMenuOption == 1){
                new CheckoutMovieMenuItem("Enter the title of the movie to checkout").execute();
            } else if(selectedSubMenuOption == 2){
                new ReturnMovieMenuItem("Enter the title of the movie to return").execute();
            }

        }

        @Override
        public String toString() {
            return description;
        }
    }

    private class CheckoutBookMenuItem {
        private final String description;

        public CheckoutBookMenuItem(String s){
            this.description = s;
        }

        public void execute(){
            if(loggedInUser != null){
                output.println(this.description);
                checkOutBook(consoleInput.next());
            } else {
                output.println("You need to be logged in to check out " + consoleInput.next());
            }
        }
    }

    private class ReturnBookMenuItem implements MenuItem
    {
        private final String description;

        public ReturnBookMenuItem(String s){
            this.description = s;
        }

        public void execute(){
            if(loggedInUser != null){
                output.println(this.description);
                returnBook(consoleInput.next());
            } else {
                output.println("You need to be logged in to return " + consoleInput.next());
            }
        }
    }

    private class CheckoutMovieMenuItem {
        private final String description;

        public CheckoutMovieMenuItem(String s) {
            this.description = s;
        }

        public void execute(){
            if(loggedInUser != null){
                output.println(this.description);
                checkOutMovie(consoleInput.next());
            } else {
                output.println("You need to be logged in to check out " + consoleInput.next());
            }
        }
    }

    private class ReturnMovieMenuItem {
        private final String description;

        public ReturnMovieMenuItem(String s) {
            this.description = s;
        }

        public void execute(){
            if(loggedInUser != null){
                output.println(this.description);
                returnMovie(consoleInput.next());
            } else {
                output.println("You need to be logged in to return " + consoleInput.next());
            }
        }
    }

    private class UserLoginMenuItem implements MenuItem {
        private final String description;

        public UserLoginMenuItem(String s) {
            this.description = s;
        }

        public void execute(){
            User user = accountManager.authenticateUserCredentials(consoleInput.next(),consoleInput.next());
            if(user != null){
                loggedInUser = user;
                output.println("You are logged in");
            } else {
                output.println("Incorrect library number and/or password");
            }
        }

        @Override
        public String toString() {
            return description;
        }
    }

    private class ViewUserDetailsMenuItem implements MenuItem {
        private final String description;

        public ViewUserDetailsMenuItem(String s) {
            this.description = s;
        }

        public void execute(){
            if(loggedInUser != null){
                output.println(loggedInUser.toString());
            } else {
                output.println("You need to be logged in to access user details");
            }
        }

        @Override
        public String toString() {
            return description;
        }
    }
}
